package o.json;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;

public class JSONFactory {
	public JSONValue create() {
		return new JSONNull();
	}
	public JSONValue create(Boolean value) {
		if (value) {
			return JSONValue.TRUE;
		} else {
			return JSONValue.FALSE;
		}
	}
	public JSONValue create(Number value) {
		if (value == null) return new JSONNull();
		return new JSONNumber(value);
	}
	public JSONValue create(String value) {
		if (value == null) return new JSONNull();
		return new JSONString(value);
	}
	public JSONValue create(Object object) {
		if (object == null) return new JSONNull();

		if (object instanceof Boolean) return create((Boolean) object);
		if (object instanceof Number) return create((Number) object);
		if (object instanceof String) return create((String) object);
		if (object instanceof Object[]) return create((Object[]) object);
		if (object instanceof Collection<?>) return create((Collection<?>) object);

		final JSONObject result = new JSONObject();
		final Class<? extends Object> c = object.getClass();
		final Method[] methods = c.getMethods();
		for (Method method : methods) {
			try {
				final String methodName = method.getName();
				if (methodName.startsWith("getClass")) continue;
				if (methodName.startsWith("getKey")) continue;
				if (method.getParameterTypes().length > 0) continue;

				if (methodName.startsWith("is")) {
					final String name = methodName.substring(2).toLowerCase();
					final JSONString key = new JSONString(name);
					method.setAccessible(true);
					final Object value = method.invoke(object);

					result.setValue(key, create(value));
				}
				if (methodName.startsWith("get")) {
					final String name = methodName.substring(3).toLowerCase();
					final JSONString key = new JSONString(name);
					method.setAccessible(true);
					final Object value = method.invoke(object);

					result.setValue(key, create(value));
				}
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}

		return result;
	}
	public JSONValue create(Object object, String[] fields) {
		if (object == null) return new JSONNull();

		final JSONObject result = new JSONObject();
		final Class<? extends Object> c = object.getClass();
		for (Field field : c.getFields()) {
			try {
				final String name = field.getName();
				if (!contains(fields, name)) continue;
				final JSONString key = new JSONString(name);
				field.setAccessible(true);
				final Object value = field.get(object);
				result.setValue(key, create(value));
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}

		return result;
	}
	private boolean contains(String[] strings, String value) {
		for (String string : strings) {
			if (value == null && string == null)
				return true;
			if (value != null && value.equals(string))
				return true;
		}

		return false;
	}

	public JSONValue create(Collection<?> array) {
		if (array == null) return new JSONNull();

		final JSONArray result = new JSONArray();
		for (Object object : array) {
			result.addValue(create(object));
		}
		return result;
	}
	public JSONValue create(Object[] array) {
		if (array == null) return new JSONNull();

		final JSONArray result = new JSONArray();
		for (Object object : array) {
			result.addValue(create(object));
		}
		return result;
	}
}
